package com.hafiery.sdk.bluetooth;

import android.bluetooth.*;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.hafiery.sdk.bluetooth.transport.adapter.NobodyAdapter;
import com.hafiery.sdk.bluetooth.transport.callback.CallBackHandler;
import com.hafiery.sdk.bluetooth.transport.callback.Callback;
import com.hafiery.sdk.bluetooth.transport.constant.ErrorCode;
import com.hafiery.sdk.bluetooth.transport.constant.OpCode;
import com.hafiery.sdk.bluetooth.transport.engine.EngineWrapper;
import com.hafiery.sdk.bluetooth.transport.engine.IEngineAction;
import com.hafiery.sdk.bluetooth.transport.req.RequestData;
import com.hafiery.sdk.bluetooth.transport.res.ResponseData;
import com.hafiery.sdk.bluetooth.util.ByteUtil;
import com.hafiery.sdk.bluetooth.util.LogUtil;

import java.util.List;
import java.util.UUID;

import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;

public class BlueToothActionImp implements IBlueToothAction{

    private final String NEW_SERVICE_UUID="000000ff-0000-1000-8000-00805f9b34fb";
    private Context mContext;
    private BluetoothAdapter mBluetoothAdapter;
    private IBlueToothActionListener blueToothActionListener;
    private CountDownTimer countDownTimer;
    private BluetoothGatt bluetoothGatt;
    private boolean isConnected;
    private UUID serviceUUid,writeCharacteristic,readCharacteristic,notifyCharacteristic;
    private EngineWrapper engineWrapper;
    private Handler handler;
    private boolean isScanning;

    public BlueToothActionImp(Context mContext,UUID serviceUUid,UUID writeCharacteristic,UUID readCharacteristic,UUID notifyCharacteristic) {
        this.handler=new Handler(Looper.getMainLooper());
        this.mContext=mContext;
        this.serviceUUid=serviceUUid;
        this.writeCharacteristic=writeCharacteristic;
        this.readCharacteristic=readCharacteristic;
        this.notifyCharacteristic=notifyCharacteristic;
        BluetoothManager mBluetoothManager= (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter=mBluetoothManager.getAdapter();

        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        mContext.registerReceiver(new BlueToothReceiver(),intentFilter);
    }
    @Override
    public void setBlueToothActionListener(IBlueToothActionListener blueToothActionListener) {
        this.blueToothActionListener = blueToothActionListener;
    }

    @Override
    public boolean isNewCard() {
        return NEW_SERVICE_UUID.equalsIgnoreCase(serviceUUid.toString());
    }
    @Override
    public boolean isSupported() {
        return mBluetoothAdapter!=null;
    }

    @Override
    public boolean isEnabled() {
        return mBluetoothAdapter.isEnabled();
    }

    @Override
    public boolean enable(boolean open) {
        return mBluetoothAdapter.enable();
    }

    @Override
    public boolean isScanning() {
        return isScanning;
    }

    @Override
    public void startScan( int timeInSeconds) {
        if(!isEnabled()){
            enable(true);
        }else{
            startTimer(timeInSeconds*1000);
            if(blueToothActionListener!=null)
                blueToothActionListener.onStartScan();
            mBluetoothAdapter.startLeScan(new UUID[]{serviceUUid},callback);
        }
    }

    @Override
    public void startScan() {
        startScan(10);
    }

    @Override
    public void stopScan() {
        stopTimer();
        mBluetoothAdapter.stopLeScan(callback);
        if(blueToothActionListener!=null)
            blueToothActionListener.onStopScan();
    }


    @Override
    public void connect(BluetoothDevice bluetoothDevice) {
        connect(bluetoothDevice,false);
    }

    @Override
    public void connect(BluetoothDevice bluetoothDevice,boolean autoConnect) {
//        disconnect(0);
        if (bluetoothGatt!=null)
            bluetoothGatt.close();
        if(blueToothActionListener!=null)
            blueToothActionListener.onGattConnectStart(bluetoothDevice);
        stopScan();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            bluetoothGatt=bluetoothDevice.connectGatt(mContext,
                    autoConnect, bluetoothGattCallback, TRANSPORT_LE);
        } else {
            bluetoothGatt=bluetoothDevice.connectGatt(mContext,
                    autoConnect, bluetoothGattCallback);
        }
    }

    @Override
    public void disconnect() {
        if(bluetoothGatt!=null){
            bluetoothGatt.disconnect();
        }
        if(engineWrapper!=null)
            engineWrapper.getTaskManager().stop();

    }

    @Override
    public boolean isConnected() {
        return isConnected;
    }

    @Override
    public <T> void write(RequestData requestData, CallBackHandler<T> callBack) {
        if(engineWrapper!=null)
            engineWrapper.send(requestData,callBack);
    }
    boolean gotoServiceDiscover =false;
    private BluetoothGattCallback bluetoothGattCallback=new BluetoothGattCallback() {

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (status==BluetoothGatt.GATT_SUCCESS){
                if (newState== BluetoothGatt.STATE_CONNECTED){
                    LogUtil.log("gatt connected!");
//                    while(!gatt.discoverServices()){
//
//                    }
//                    while(!gotoServiceDiscover){
//                        try {
//                            Thread.sleep(1000);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        if(!gotoServiceDiscover)
//                            gatt.discoverServices();
//                    }
                    LogUtil.log("开始执行发现服务");
                    gatt.discoverServices();
                }
                else if(newState == BluetoothGatt.STATE_DISCONNECTED){
                    LogUtil.log("gatt disconnect!");
                    handler.post(()->{
                        gatt.close();
                        if(engineWrapper!=null)
                            engineWrapper.getTaskManager().stop();
                    });
                }
            }else{
                LogUtil.log("gatt disconnect with status ->"+status);
                handler.post(() -> {
                    isConnected=false;
                    disconnect();
                    if(blueToothActionListener!=null){
                        blueToothActionListener.onGattConnectError(status);
                    }
                });
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            LogUtil.log("onServicesDiscovered:"+status+","+isNewCard());
            if (status != BluetoothGatt.GATT_SUCCESS || gatt.getService(serviceUUid)==null){
                LogUtil.log("无法发现服务,请重新连接");
                if(blueToothActionListener!=null){
                    blueToothActionListener.onGattConnectError(22);
                }
                return;
            }
            if(isNewCard()){
                boolean b=gatt.setCharacteristicNotification(gatt.getService(serviceUUid).getCharacteristic(notifyCharacteristic),true);
                LogUtil.log("开启通知:"+b);
                handler.post(() -> {
                    isConnected=true;
                    BluetoothGattCharacteristic charaWrite=gatt.getService(serviceUUid).getCharacteristic(writeCharacteristic);
                    charaWrite.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
                    engineWrapper=new EngineWrapper(gatt,charaWrite);
                    if(blueToothActionListener!=null){
                        blueToothActionListener.onGattConnected(gatt.getDevice());
                    }
                });
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        LogUtil.log("发送握手");
                        //握手
                        shakeHands();
                    }
                },3*1000);
                bluetoothGatt.requestMtu(512);
            }else{
                handler.post(() -> {
                    isConnected=true;
                    BluetoothGattCharacteristic charaWrite=gatt.getService(serviceUUid).getCharacteristic(writeCharacteristic);
                    charaWrite.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
                    engineWrapper=new EngineWrapper(gatt,charaWrite);
                    //设置notify
                    BluetoothGattCharacteristic charaNotify=gatt.getService(serviceUUid).getCharacteristic(notifyCharacteristic);
                    boolean b=gatt.setCharacteristicNotification(charaNotify, true);
                    if(b){
                        List<BluetoothGattDescriptor> mm = charaNotify.getDescriptors();
                        for (BluetoothGattDescriptor bluetoothGattDescriptor : mm) {
                            bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                            gatt.writeDescriptor(bluetoothGattDescriptor);
                        }
                        LogUtil.log("通知开启成功");
                    }else{
                        LogUtil.log("通知开启失败");
                    }

                    if(blueToothActionListener!=null){
                        blueToothActionListener.onGattConnected(gatt.getDevice());
                    }
                });
            }

        }

//        @Override
//        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//            super.onServicesDiscovered(gatt, status);
//            LogUtil.log("onServicesDiscovered:"+status);
//            gatt.setCharacteristicNotification(gatt.getService(serviceUUid).getCharacteristic(notifyCharacteristic),true);
//            handler.post(() -> {
//                isConnected=true;
//                BluetoothGattCharacteristic charaWrite=bluetoothGatt.getService(serviceUUid).getCharacteristic(writeCharacteristic);
//                charaWrite.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
//                engineWrapper=new EngineWrapper(bluetoothGatt,charaWrite);
//                //设置notify
////                BluetoothGattCharacteristic charaNotify=bluetoothGatt.getService(serviceUUid).getCharacteristic(notifyCharacteristic);
////                boolean b=gatt.setCharacteristicNotification(charaNotify, true);
////                if(b){
////                    List<BluetoothGattDescriptor> mm = charaNotify.getDescriptors();
////                    for (BluetoothGattDescriptor bluetoothGattDescriptor : mm) {
////                        bluetoothGattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
////                        gatt.writeDescriptor(bluetoothGattDescriptor);
////                    }
////                    LogUtil.log("通知开启成功");
////                }else{
////                    LogUtil.log("通知开启失败");
////                }
//                if(blueToothActionListener!=null){
//                    blueToothActionListener.onGattConnected(bluetoothGatt.getDevice());
//                }
//                //握手
//                shakeHands();
//            });
//            bluetoothGatt.requestMtu(512);
//        }
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            byte[] receivedBytes=characteristic.getValue();
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < receivedBytes.length; i++) {
                sb.append(String.format("%02x", receivedBytes[i]));
            }
            LogUtil.log("收到数据:"+sb);
            handler.post(() -> engineWrapper.received(ResponseData.fromValue(characteristic.getValue())));
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            LogUtil.log("onDescriptorWrite: " + status);
            shakeHands();
        }

    };

    private BluetoothAdapter.LeScanCallback callback=new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            if(blueToothActionListener!=null)
                blueToothActionListener.onScanResult(device,rssi);
        }
    };

    private void startTimer(int timeInMilliseconds){
        if(isScanning){
            return;
        }
        isScanning=true;
        countDownTimer=new CountDownTimer(timeInMilliseconds,1000) {
            @Override
            public void onTick(long millisUntilFinished) {
            }
            @Override
            public void onFinish() {
                stopScan();
            }
        };
        countDownTimer.start();
    }
    private void stopTimer(){
        if(!isScanning){
            return;
        }
        isScanning=false;
        if(countDownTimer!=null){
            countDownTimer.cancel();
            countDownTimer=null;
        }
    }

    private class BlueToothReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action=intent.getAction();
            switch (action){
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    int blueNewState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                    switch (blueNewState){
                        case BluetoothAdapter.STATE_TURNING_ON:
                            break;
                        case BluetoothAdapter.STATE_ON:
                            if(blueToothActionListener!=null)
                                blueToothActionListener.onBlueToothOpenOrCloseStatusChanged(true);
                            break;
                        case BluetoothAdapter.STATE_TURNING_OFF:
                            break;
                        case BluetoothAdapter.STATE_OFF:
                            isConnected=false;
                            if(blueToothActionListener!=null)
                                blueToothActionListener.onBlueToothOpenOrCloseStatusChanged(false);
                            break;
                    }
                    break;
                case BluetoothDevice.ACTION_ACL_CONNECTED:
                    break;
                case BluetoothDevice.ACTION_ACL_DISCONNECTED:
                    isConnected=false;
                    if(blueToothActionListener!=null)
                        blueToothActionListener.onGattConnectDisconnect();
                    break;
            }

        }
    }

    private void shakeHands(){
        String[] address = bluetoothGatt.getDevice().getAddress().split(":");
        byte[] code = new byte[address.length];
        for (int i = address.length - 1, t = 0; i>=0; i--) {
            byte v = ByteUtil.stringToHex(address[i]);
            code[t++] = (byte) (v^0x0A5);
        }
        write(new RequestData.Builder()
                .cmd(OpCode.SHAKE_HANDS)
                .payload(code)
                .build(),new CallBackHandler(new Callback() {
            @Override
            public void onSuccess(Object data) {
                handler.post(() -> {
                    if(blueToothActionListener!=null)
                        blueToothActionListener.onShakeHandsSuccess();
                });
            }
            @Override
            public void onFailure(ErrorCode errorCode) {
                handler.post(() -> {
                    if(blueToothActionListener!=null)
                        blueToothActionListener.onShakeHandsFailed(errorCode);
                });
            }
        },new NobodyAdapter()));
    }
}
